%{
#include <string.h>
#include <stdlib.h>
//#include <js/jsapi.h>
//#include "main.h"

#define YY_EXTRA_TYPE struct Extra *

//#define ECHO yyextra->y = yytext; while(*yyextra->y) *(yyextra->b++) = *(yyextra->y++)

#define ECHO


struct Extra {
	char *buf;
	char *buf_ptr;
	char *attribute_name;
	char *tagName;
	char **stack;
	char **stack_ptr;
	int indent;
};


struct Extra *create_extra() {
	struct Extra *extra = (struct Extra *)calloc(sizeof(struct Extra), 1);
	extra->buf = (char *)calloc(sizeof(char) * 100000, 1);
	extra->buf_ptr = extra->buf;
	extra->stack = (char **)calloc(sizeof(char *) * 1000, 1);
	extra->stack_ptr = extra->stack;
	return extra;
}

void init_buffer(YY_EXTRA_TYPE extra) {
	extra->buf_ptr = extra->buf;
	*extra->buf_ptr = 0;
}

void write_buffer(YY_EXTRA_TYPE extra, char *text) {
	while (*text) {
		switch (*text) {
			//case '\'': strcat(extra->buf_ptr, "\\\'"); extra->buf_ptr += 2; break;
			//case '\"': strcat(extra->buf_ptr, "\\\""); extra->buf_ptr += 2; break;
			//case '\\': strcat(extra->buf_ptr, "\\\\"); extra->buf_ptr += 2; break;
			default: *(extra->buf_ptr++) = *text; break;
		}
		++text;
	}
	*extra->buf_ptr = 0;
}

char *get_buffer(YY_EXTRA_TYPE extra) {
	return extra->buf_ptr = extra->buf;
}


void indent(int n) {
	if(n < 0) {
		printf("//");
		return;
	}
	for(; n > 0; --n)
		printf("    ");
}


void create_element(YY_EXTRA_TYPE extra, char *text) {
	indent(extra->indent);
	printf(";Html.open('%s')\n", text, text);	
	extra->indent++;
	extra->tagName = *(++extra->stack_ptr) = strdup(text);
}

void create_text(YY_EXTRA_TYPE extra, char *text) {
	if(!*text) return;
	indent(extra->indent);
	printf(".text('%s')\n", text);
	//printf("%s.appendChild(document.createTextNode('%s'));\n", extra->tagName, text);
}

void create_attribute(YY_EXTRA_TYPE extra, char *text) {
	//printf("create_attribute('%s')\n", text);
	extra->attribute_name = strdup(text);
}

void set_attribute_value(YY_EXTRA_TYPE extra, char *text) {
	if(extra->attribute_name) {
		indent(extra->indent);
		printf(".attr('%s', '%s')\n", extra->attribute_name, text);
		
		//printf("%s['%s'] = '%s';\n", extra->tagName, extra->attribute_name, text);
		//printf("%s.setAttribute('%s', '%s');\n", extra->tagName, extra->attribute_name, text);
	}
}




//%option extra-type="struct Buffer *"

%}

%option stack 
%option case-insensitive
%option noyywrap
%option reentrant

%x tag attr1 attr2 attr3 attr3_qstring attr3_dqstring doctype comment attr0 decimal_code

%%

<decimal_code>[0-9]+      { char out[20] = ""; sprintf(out, "\\u%04x", atoi(yytext)); write_buffer(yyextra, out); }
<decimal_code>.           yy_pop_state(yyscanner);

[ \r\n\t]+                write_buffer(yyextra, " "); BEGIN(INITIAL);

"&nbsp;"   write_buffer(yyextra, "\\u00a0");
"&quot;"   write_buffer(yyextra, "\"");
"&amp;"    write_buffer(yyextra, "&");
"&lt;"     write_buffer(yyextra, "<");
"&gt;"     write_buffer(yyextra, ">");
"&copy;"   write_buffer(yyextra, "\\u00a9");
"&laquo;"  write_buffer(yyextra, "\\u00ab");
"&reg;"    write_buffer(yyextra, "\\u00ae");


"&#"                      yy_push_state(decimal_code, yyscanner); 
"\'"					  write_buffer(yyextra, "\\\'"); BEGIN(INITIAL);
"\""                      write_buffer(yyextra, "\\\""); BEGIN(INITIAL);

"<!--"                    create_text(yyextra, get_buffer(yyextra)); init_buffer(yyextra); BEGIN(comment);
"<!"                      create_text(yyextra, get_buffer(yyextra)); init_buffer(yyextra); BEGIN(doctype);

"</"[-a-zA-Z0-9_:]+">"  {
							create_text(yyextra, get_buffer(yyextra));
							init_buffer(yyextra);
							//yytext += 2;
							//yytext[strlen(yytext) - 1] = 0;
							--yyextra->indent;
							indent(yyextra->indent);
							yyextra->tagName = *(--yyextra->stack_ptr);
							printf(".close()\n");
							//printf("})(%s);\n", yyextra->tagName);
							//indent(yyextra->indent);
							//printf("/* /%s, %s */\n", yytext, yyextra->tagName);
							//indent(yyextra->indent);
							//printf("%s = %s.parentNode;\n", yyextra->tagName, yytext);
							BEGIN(INITIAL);
						}


"<"                     {
							create_text(yyextra, get_buffer(yyextra));
							init_buffer(yyextra);
							BEGIN(tag);
						}
						
.                         write_buffer(yyextra, yytext); BEGIN(INITIAL);

<doctype>">"              BEGIN(INITIAL);
<doctype>.                BEGIN(doctype);

<comment>"-->"            BEGIN(INITIAL);
<comment>.                BEGIN(comment);

<tag>"html"               BEGIN(attr1);
<tag>"meta"|"br"|"link"|"input"  create_element(yyextra, yytext); BEGIN(attr0);
<tag>[-a-zA-Z0-9_:]+ 	  create_element(yyextra, yytext); BEGIN(attr1);


<attr0>"/>"|">"         {
							--yyextra->stack_ptr;
							--yyextra->indent;
							indent(yyextra->indent);
							yyextra->tagName = *yyextra->stack_ptr;
							printf(".close()\n");
							//printf("})(%s);\n", yyextra->tagName);
							BEGIN(INITIAL);
						}
<attr0>[ \r\n\t]+         BEGIN(attr0);
<attr0>[-a-zA-Z0-9]+      create_attribute(yyextra, yytext); yy_push_state(attr2, yyscanner);



<attr1>"/>"             {
							--yyextra->stack_ptr;
							--yyextra->indent;
							indent(yyextra->indent);
							yyextra->tagName = *yyextra->stack_ptr;
							printf(".close()\n");
							//printf("})(%s);\n", yyextra->tagName);
							//indent(yyextra->indent);
							//printf("%s = %s.parentNode;\n", *yyextra->stack_ptr, yyextra->tagName);
							
							BEGIN(INITIAL);
						}
							
<attr1>">"                BEGIN(INITIAL);
<attr1>[ \r\n\t]+         BEGIN(attr1);
<attr1>[-a-zA-Z0-9]+      create_attribute(yyextra, yytext); yy_push_state(attr2, yyscanner);

<attr2>[ \r\n\t]+         BEGIN(attr2);
<attr2>"="                BEGIN(attr3);
<attr2>[-a-zA-Z0-9]+      set_attribute_value(yyextra, "true"); create_attribute(yyextra, yytext); yy_pop_state(yyscanner);

<attr3>[ \r\n\t]+         BEGIN(attr3);
<attr3>"\'"               init_buffer(yyextra); BEGIN(attr3_qstring);
<attr3>"\""               init_buffer(yyextra); BEGIN(attr3_dqstring);
<attr3>[-a-zA-Z0-9_%]+    set_attribute_value(yyextra, yytext); yy_pop_state(yyscanner);

<attr3_qstring>"\\\'"     write_buffer(yyextra, "'"); BEGIN(attr3_qstring);
<attr3_qstring>"\'"       set_attribute_value(yyextra, get_buffer(yyextra)); init_buffer(yyextra); yy_pop_state(yyscanner);
<attr3_qstring>[^\']+     write_buffer(yyextra, yytext); BEGIN(attr3_qstring);

<attr3_dqstring>"\\\""    write_buffer(yyextra, "\""); BEGIN(attr3_dqstring);
<attr3_dqstring>"\""      set_attribute_value(yyextra, get_buffer(yyextra)); init_buffer(yyextra); yy_pop_state(yyscanner);
<attr3_dqstring>[^\"]+    write_buffer(yyextra, yytext); BEGIN(attr3_dqstring);


%%

main() {
	char *str;
	str = (char *)malloc(1000000);
	
	size_t len = fread(str, 1, 1000000, stdin);
	str[len] = 0;
	
	//printf("str: %s\n", str);
	//return 0;

	YY_EXTRA_TYPE extra = create_extra();
	
	printf("Html\n");
	//extra->tagName = *(++extra->stack_ptr) = strdup("html");
	//++extra->indent;
	
	
				
	yyscan_t scanner;
	yylex_init(&scanner);

	yyset_extra(extra, scanner);
	YY_BUFFER_STATE s = yy_scan_string(str, scanner);
	yy_switch_to_buffer(s, scanner);
	//yyset_in(stream, scanner);

	yylex(scanner);
	yylex_destroy(scanner);
}


